package de.koller.oceanFramework.math;

public class RVec2d {
	public double x, y;
	
	public RVec2d() {
		this.clear();
	}
	
	public RVec2d( double x, double y ) {
		this.set( x, y );
	}
	
	public RVec2d( RVec2d o ) {
		this.set( o );
	}
	
	public double getDirection() {
		return Math.atan2( y, x );
	}
	
	public RVec2d setLength( double l ) {
		setTo( getDirection(), l );
		return this; 
	}
	
	public RVec2d setDirection( double d ) {
		return setTo( d, getLength() );
	}
	
	public RVec2d setTo( double direction, double length ) {
		this.x = Math.cos( direction ) * length;
		this.y = Math.sin( direction ) * length;
		return this;
	}
	
	public final RVec2d set( RVec2d o ) {
		this.x = o.x;
		this.y = o.y;
		return this;
	}
	
	public final RVec2d set( double x, double y ) {
		this.x = x;
		this.y = y;
		return this;
	}
	
	public final RVec2d clear() {
		this.x = 0;
		this.y = 0;
		return this;
	}
	
	public final RVec2d add( double x, double y ) {
		this.x += x;
		this.y += y;
		return this;
	}
	
	public final RVec2d add( RVec2d o ) {
		return add( o.x, o.y );
	}
	
	public final RVec2d sub( RVec2d o ) {
		this.x -= o.x;
		this.y -= o.y;
		return this;
	}
	
	public final RVec2d mult( double s ) {
		this.x *= s;
		this.y *= s;
		return this;
	}
	
	public static RVec2d difference( RVec2d a, RVec2d b ) {
		return a.newInstace().sub( b );
	}
	
	public final RVec2d negate() {
		this.x = -this.x;
		this.y = -this.y;
		return this;
	}
	
	public final RVec2d newInstace() {
		return new RVec2d( this );
	}
	
	@Override
	public String toString() {
		return "( " + x + ", " + y + " )";
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		long result = 1;
		result = prime * result + Double.doubleToLongBits(x);
		result = prime * result + Double.doubleToLongBits(y);
		return (int)result;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		RVec2d other = (RVec2d)obj;
		if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
			return false;
		if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
			return false;
		return true;
	}
	
	public static double dot( RVec2d a, RVec2d b ) {
		return a.x * b.x + a.y * b.y;
	}
	
	public final double getLength() {
        return Math.sqrt( this.getLengthSquared() );
    }

    public final double getLengthSquared() {
        return x * x + y * y;
    }
	
	public final RVec2d normalize() {
		double length = getLengthSquared();
        if( length != 1f && length != 0f ) {
            length = 1f / Math.sqrt( length );
            return this.mult( length );
        } 
		return this;
	}
	
	public static double getAngle( RVec2d a, RVec2d b ) {
        double dotProduct = dot( a, b );
        double angle = (double)Math.acos( dotProduct );
        return angle;
    }
	
}
